import java.util.Enumeration;
import java.util.Vector;


public class CopyOfNo {
	
	private String simbolo;
	private Vector<CopyOfNo> filhos;
	private int quantidade;
	private CopyOfNo pai;
	boolean calcula;
	
	public CopyOfNo(String s) {
		simbolo = s;
		quantidade = 1;
		filhos = null;
		pai = null;
		calcula = true;
	}
	
	public void adiciona(String s) {
//		this.exibir("");
//		System.out.println("ADICIONAR " + s.charAt(s.length()-1) + " NO CONTEXTO " 
//				+ s.substring(0, s.length()-1));
		if (s.length()>1) {
			// se nao existir o contexto onde se est� trabalhando, reduz o contexto.
			
			if (!existeContexto(s)){
				this.adiciona(s.substring(1, s.length()));
			}
		}
		else {
			if (filhos == null)
				filhos = new Vector<CopyOfNo>();
			Enumeration<CopyOfNo> e = filhos.elements();
			boolean adicionar = true;
			while (e.hasMoreElements()) {
				CopyOfNo aux =  e.nextElement();
				if (s.startsWith(aux.simbolo)) {
					if (Codificador.getInstance().codifica) {
						calcula(aux.simbolo);
						Codificador.getInstance().codifica = false;
					}
					adicionar = false;
					aux.incrementa();
//					System.out.println("Incrementa : "+aux.simbolo);
					break;
				}
			}
			if (adicionar) {
				CopyOfNo aux = new CopyOfNo(s);
				aux.setPai(this);
				if (filhos.size()==0) {
					filhos.add(new CopyOfNo("esc"));
				}
				else {
					calcula("esc");
					CopyOfNo aux2 = localiza(filhos,"esc");
					aux2.incrementa();
				}
				//System.out.println("Consultando a probabilidade da tabela de ignorancia para o simbolo "+aux.simbolo);
				Codificador.getInstance().codificar(TabelaIgnorancia.getInstance().probSimbolo(aux.simbolo.charAt(0)));
				filhos.add(aux);
			}
		}
		calcula = true;
	//	System.out.println("\n\n\n");
	}
	
	public boolean equals(Object o) {
		CopyOfNo a = (CopyOfNo)o;
		return (simbolo.equals(a.simbolo));
	}
	
	public CopyOfNo localiza(Vector<CopyOfNo> filhos, String no) {
		Enumeration<CopyOfNo> e = filhos.elements();
		while (e.hasMoreElements()) {
			CopyOfNo aux =  e.nextElement();
			if (no.equals(aux.simbolo)) {
				return aux;
			}
		}
		return null;
	}
	
	public boolean existeContexto(String s) {
//		if (pai != null)
//			System.out.println(" pai = "+pai.simbolo+" simbolo = "+simbolo);
//		else
//			System.out.println(" pai = null  simbolo = "+simbolo);
//		System.out.println("Entrou aqui com a string : "+s);
		if ((filhos!=null)&&(filhos.size()>0)) {
			Enumeration<CopyOfNo> e = filhos.elements();
			while (e.hasMoreElements()) {
				CopyOfNo aux =  e.nextElement();
				if (s.startsWith(aux.simbolo)) {
					if ((aux.filhos == null)&&(s.length()>1)) {
//						System.out.println("Entrando aqui... sem filhos e com s = "+s);
						aux.filhos = new Vector<CopyOfNo>();
						CopyOfNo aux2 = new CopyOfNo(s.substring(1, 2));
						aux2.setPai(this);
						CopyOfNo aux3 = new CopyOfNo("esc");
						aux3.setPai(this);
						
						aux.filhos.add(aux2);
						aux.filhos.add(aux3);
						return false;
					}
					else if (s.length()<=1) {
						aux.incrementa();
						return true;
					}
					else {
						if ((s.length()>2)&&(aux.existeContexto(s.substring(1, s.length())))) {
							return true;
						}
						else {
							
							if (s.length()>2) {
//								System.out.println("ENTROU AQUI COM s MAIOR QUE 2!!!!!!");
								return false;
							}
										
							if (s.length()==2) {
								
								CopyOfNo aux5 = localiza(aux.filhos, s.substring(1, 2));
//								System.out.println("Procurando contexto "+s.substring(1, 2)+" no nó "+aux.simbolo);
								if (aux5!=null) {
									if (Codificador.getInstance().codifica) {
										aux.calcula(s.substring(1, 2));
										Codificador.getInstance().codifica = false;
									}
//									System.out.println("encontrou : "+aux5.simbolo+ " e vai incrementa-lo");
									aux5.incrementa();
									calcula = false;
								}
								else {
									aux.calcula("esc");
									CopyOfNo aux2 = new CopyOfNo(s.substring(1, 2));
									CopyOfNo aux3 = localiza(aux.filhos, "esc");
									aux3.incrementa();
									aux.filhos.add(aux2);
								}
								return false;
							}
							else
								return false;
						}
					}
				}
			}
			CopyOfNo aux = new CopyOfNo(s.substring(0, 1));
			aux.setPai(this);
			filhos.add(aux);
			return false;
		}
		else
			return false;
	}
	
	public void setPai(CopyOfNo n) {
		pai = n;
	}
	
	public void calcula(String s) {
		
		
	//	System.out.println("calcula probabilidade do simbolo: "+s);
	//	System.out.println("nos elementos : ");
		
	
		boolean achou = false;
		int frequenciaAcumulada=0;
		
		int[] dados = new int[3];
		
		dados[0] = dados[1] = dados[2] = 0;
		
		Enumeration<CopyOfNo> e = ordenar(filhos).elements();

		
		//No[] lista = (No[])arvore.toArray();
		//Arrays.sort(lista);
		
		while (e.hasMoreElements()) {
			CopyOfNo aux =  e.nextElement();
			
			
			//System.out.println(aux.simbolo+" - "+aux.quantidade);
			
			
			if( ((aux.simbolo).equals(s)) && !achou ){
				achou = true;
				dados[0] = frequenciaAcumulada; 
				dados[1] = frequenciaAcumulada + aux.quantidade;
			}
			frequenciaAcumulada += aux.quantidade;
		}
		
		dados[2] = frequenciaAcumulada;
		
	//	System.out.println("DADOS: " + s + " LOW: " + dados[0] + " HIGH: " + dados[1] + " TOTAL: " + dados[2]);
		Codificador.getInstance().codificar(dados);
	
	}
	
	public Vector<CopyOfNo> ordenar(Vector<CopyOfNo> lista) {		
		int i, j, menor;
		CopyOfNo tmp;

		for (i = 0 ; i < lista.size() ; i++) 	{
			menor = i;
			for (j = i + 1 ; j<lista.size() ; j++)	{
				if (lista.elementAt(i).simbolo.compareTo(lista.elementAt(j).simbolo) < 0)
					menor = j;
			}
			tmp = lista.elementAt(i);
			lista.setElementAt(lista.elementAt(menor), i);
			lista.setElementAt(tmp, menor);
	    }
		
		return lista; 
	}
	
	public void incrementa() {
		quantidade++;
	}
	
	public void exibir(String espaco) {
		int cont=0;
		System.out.println(espaco+simbolo+"-"+quantidade);
		if ((filhos!=null)&&(filhos.size()>0)) {
			Enumeration<CopyOfNo> e = filhos.elements();
			while (e.hasMoreElements()) {
				CopyOfNo aux =  e.nextElement();
				aux.exibir(espaco+"\t|");
				cont += aux.quantidade;
			}
			System.out.println(espaco + "\t|" + "TOTAL " + cont);
		}
		
	}

}